import _ from 'lodash';
import { Observable } from 'rx';
import debugFactory from 'debug';
import dedent from 'dedent';

import { homeLocation } from '../../../config/env';

import nonprofits from '../utils/commit.json';
import { commitGoals, completeCommitment$ } from '../utils/commit';

import { unDasherize } from '../../../utils/slugs';

import { observeQuery, saveInstance } from '../utils/rx';

import { ifNoUserRedirectTo } from '../utils/middleware';

const sendNonUserToSignIn = ifNoUserRedirectTo(
  `${homeLocation}/signin`,
  'You must be signed in to commit to a nonprofit.',
  'info'
);

const sendNonUserToCommit = ifNoUserRedirectTo(
  '/commit',
  'You must be signed in to update commit',
  'info'
);

const debug = debugFactory('fcc:commit');

function findNonprofit(name) {
  let nonprofit;
  if (name) {
    nonprofit = _.find(nonprofits, nonprofit => {
      return name === nonprofit.name;
    });
  }

  nonprofit = nonprofit || nonprofits[_.random(0, nonprofits.length - 1)];
  return nonprofit;
}

export default function commit(app) {
  const router = app.loopback.Router();
  const api = app.loopback.Router();
  const { Pledge } = app.models;

  router.get('/commit', commitToNonprofit);

  router.get('/commit/pledge', sendNonUserToSignIn, pledge);

  router.get('/commit/directory', renderDirectory);

  api.post('/commit/stop-commitment', sendNonUserToCommit, stopCommit);

  api.post('/commit/complete-goal', sendNonUserToCommit, completeCommitment);

  app.use(api);
  app.use(router);

  function commitToNonprofit(req, res, next) {
    const { user } = req;
    let nonprofitName = unDasherize(req.query.nonprofit);

    debug('looking for nonprofit', nonprofitName);
    const nonprofit = findNonprofit(nonprofitName);

    Observable.just(user)
      .flatMap(user => {
        if (user) {
          debug('getting user pledge');
          return observeQuery(user, 'pledge');
        }
        return Observable.just();
      })
      .subscribe(pledge => {
        if (pledge) {
          debug('found previous pledge');
          req.flash(
            'info',
            dedent`
                Looks like you already have a pledge to ${pledge.displayName}.
                Clicking "Commit" here will replace your old commitment. If you
                do change your commitment, please remember to cancel your
                previous recurring donation directly with ${pledge.displayName}.
              `
          );
        }
        res.render('commit/', {
          title: 'Commit to a nonprofit. Commit to your goal.',
          pledge,
          ...commitGoals,
          ...nonprofit
        });
      }, next);
  }

  function pledge(req, res, next) {
    const { user } = req;
    const {
      nonprofit: nonprofitName = 'girl develop it',
      amount = '5',
      goal = commitGoals.respWebDesignCert
    } = req.query;

    const nonprofit = findNonprofit(nonprofitName);

    observeQuery(user, 'pledge')
      .flatMap(oldPledge => {
        // create new pledge for user
        const pledge = Pledge({
          amount,
          goal,
          userId: user.id,
          ...nonprofit
        });

        if (oldPledge) {
          debug('user already has pledge, creating a new one');
          // we orphan last pledge since a user only has one pledge at a time
          oldPledge.userId = '';
          oldPledge.formerUser = user.id;
          oldPledge.endDate = new Date();
          oldPledge.isOrphaned = true;
          return saveInstance(oldPledge).flatMap(() => {
            return saveInstance(pledge);
          });
        }
        return saveInstance(pledge);
      })
      .subscribe(({ displayName, goal, amount }) => {
        req.flash(
          'success',
          dedent`
              Congratulations, you have committed to giving
              ${displayName} $${amount} each month until you have completed
              your ${goal}. Please remember to cancel your pledge directly
              with ${displayName} once you finish.
            `
        );
        res.redirect('/' + user.username);
      }, next);
  }

  function renderDirectory(req, res) {
    res.render('commit/directory', {
      title: 'Commit Directory',
      nonprofits
    });
  }

  function completeCommitment(req, res, next) {
    const { user } = req;

    return completeCommitment$(user).subscribe(msgOrPledge => {
      if (typeof msgOrPledge === 'string') {
        return res.send(msgOrPledge);
      }
      return res.send(true);
    }, next);
  }

  function stopCommit(req, res, next) {
    const { user } = req;

    observeQuery(user, 'pledge')
      .flatMap(pledge => {
        if (!pledge) {
          return Observable.just();
        }

        pledge.formerUserId = pledge.userId;
        pledge.userId = null;
        pledge.isOrphaned = true;
        pledge.dateEnded = new Date();
        return saveInstance(pledge);
      })
      .subscribe(pledge => {
        let msg = dedent`
            You have successfully stopped your pledge. Please
            remember to cancel your recurring donation directly
            with the nonprofit if you haven't already done so.
          `;
        if (!pledge) {
          msg = dedent`
              It doesn't look like you had an active pledge, so
              there's no pledge to stop.
            `;
        }
        req.flash('info', msg);
        return res.redirect(`/${user.username}`);
      }, next);
  }
}
